package com.siashan.unipay4j.ali.transfer;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.siashan.unipay4j.ali.AbstractAliPay;
import com.siashan.unipay4j.ali.AliConstants;
import com.siashan.unipay4j.core.IPayConfig;
import com.siashan.unipay4j.core.Result;
import com.siashan.unipay4j.core.exception.Unipay4jOperationNotSupportedException;
import com.siashan.unipay4j.core.transfer.*;
import com.siashan.unipay4j.core.util.EnumUtil;
import com.siashan.unipay4j.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * 支付宝转账
 *
 * @author siashan
 * @since v1.0.1
 **/
@Slf4j
public class AliPayTransfer extends AbstractAliPay implements ITransfer {

    public AliPayTransfer() {
    }

    public AliPayTransfer(IPayConfig payConfig) {
        super(payConfig);
    }

    /**
     * 单笔转账到账户余额
     *
     * @param model   转账实体
     * @return 转账结果
     */
    @Override
    public Result<TransferResp> execTransferToAccount(TransferToAccountModel model) {
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        request.setBizContent(JSON.toJSONString(wrapParam2Account(model)));
        try {
            AlipayFundTransUniTransferResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                return Result.tradeSuccess(wrapperResponse(response));
            } else {
                return Result.tradeFail(response.getSubCode(), response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return Result.exception();
    }

    @Override
    public Result<TransferResp> execTransferToAccount(TransferRequestModel model) {
        throw new Unipay4jOperationNotSupportedException("支付宝支付暂不支持该接口");
    }

    /**
     * 单笔转账到银行卡
     * 描述：
     * B2C转账接口，通过调用该接口将资金打款至收款人银行卡
     * 场景：
     * 商户调用该接口将资金从发起请求的商户支付宝账户打款给指定的收款人银行卡
     * 申请条件
     * 商户签约仅支持注册满 90 天，且已实名认证的企业支付宝账户签约，暂不支持个体工商户及个人支付宝账户。
     * 本产品定向开放，请联系支付宝业务人员签约 单笔转账到银行卡（无密）。
     * @param model  转账请求实体
     * @return 转账结果
     */
    @Override
    public Result<TransferResp> execTransferToBank(TransferToBankModel model) {
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        request.setBizContent(JSON.toJSONString(wrapParam2Bank(model)));
        try {
            AlipayFundTransUniTransferResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                return Result.tradeSuccess(wrapperResponse(response));
            } else {
                return Result.tradeFail(response.getSubCode(), response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return Result.exception();
    }


    /**
     * 封装请求参数
     *
     * @param model  转账请求实体
     * @return 请求参数
     */
    private Map<String, Object> wrapParam2Bank(TransferToBankModel model) {
        Map<String, Object> map = new HashMap<>();
        map.put("out_biz_no", model.getOutTradeNo());
        map.put("trans_amount", model.getAmount());
        map.put("product_code", AliConstants.ProductCode.TRANS_BANKCARD_NO_PWD);
        map.put("biz_scene", AliConstants.BizScene.DIRECT_TRANSFER);
        if (StrUtil.isNotEmpty(model.getRemark())) {
            map.put("remark", model.getRemark());
        }
        if (StrUtil.isNotEmpty(model.getTitle())) {
            map.put("order_title", model.getTitle());
        }
        // 收款方信息
        Map<String, Object> payeeInfo = new HashMap<>();
        payeeInfo.put("identity", model.getBankNo());
        payeeInfo.put("identity_type", AliConstants.IdentityType.BANKCARD_ACCOUNT);
        payeeInfo.put("name", model.getAccountName());
        // 收款方银行卡扩展信息
        Map<String, Object> bankcardExtInfo = new HashMap<>();
        bankcardExtInfo.put("inst_name", model.getBankNo());
        bankcardExtInfo.put("account_type", BankAccountType.PRIVATE.equals(model.getAccountType()) ? AliConstants.AccountType.PRIVATE : AliConstants.AccountType.CORPORATE);

        payeeInfo.put("bankcard_ext_info", bankcardExtInfo);
        map.put("payee_info", payeeInfo);
        return map;
    }

    /**
     * 封装请求参数
     *
     * @param model  转账请求实体
     * @return 请求参数
     */
    private Map<String, Object> wrapParam2Account(TransferToAccountModel model) {
        Map<String, Object> map = new HashMap<>();
        map.put("out_biz_no", model.getOutTradeNo());
        map.put("trans_amount", model.getAmount());
        map.put("product_code", AliConstants.ProductCode.TRANS_ACCOUNT_NO_PWD);
        map.put("biz_scene", AliConstants.BizScene.DIRECT_TRANSFER);
        if (StrUtil.isNotEmpty(model.getRemark())) {
            map.put("remark", model.getRemark());
        }
        if (StrUtil.isNotEmpty(model.getTitle())) {
            map.put("order_title", model.getTitle());
        }
        // 收款方信息
        Map<String, Object> payeeInfo = new HashMap<>();
        payeeInfo.put("identity", model.getIdentity());
        payeeInfo.put("identity_type", com.siashan.unipay4j.core.transfer.IdentityType.USER_ID.equals(model.getIdentityType()) ? AliConstants.IdentityType.ALIPAY_USER_ID : AliConstants.IdentityType.ALIPAY_LOGON_ID);
        //参与方真实姓名，如果非空，将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时，本字段必填。
        if (StrUtil.isNotEmpty(model.getReUserName())) {
            payeeInfo.put("name", model.getReUserName());
        }
        map.put("payee_info", payeeInfo);
        return map;
    }


    /**
     * 封装转账结果
     *
     * @param r  支付宝返回结果
     * @return 转账结果
     */
    private TransferResp wrapperResponse(AlipayFundTransUniTransferResponse r) {
        AliTransferState stateEnum = EnumUtil.getIEnum(AliTransferState.class, r.getStatus());
        TransferResp response = new TransferResp();
        response.setTransferState(stateEnum.getTransferState());
        response.setOutTradeNo(r.getOutBizNo());
        response.setTradeNo(r.getOrderId());
        response.setBody(JSON.toJSONString(r));
        return response;
    }
}
